﻿using System;
using System.IO;
using System.Xml.Serialization;
using Microsoft.Xna.Framework.Input;

namespace SpaceshipDuel
{
    /// <summary>
    /// Struktur für Tastensteuerung
    /// </summary>
    public struct PlayerKeys
    {
        public Keys upKey;
        public Keys downKey;
        public Keys leftKey;
        public Keys rightKey;
        public Keys fireKey;
        public Keys specialKey;
    }

    /// <summary>
    /// Bereitstellung der Konfigurationsdaten
    /// (Einstellungen Grafik, Sound, Steuerung)
    /// </summary>
    static class ConfigDataHelper
    {
        #region Private fields

        private static ConfigData myData;
        private static PlayerKeys player1Keys;
        private static PlayerKeys player2Keys;

        private static bool setPlayer1Keys;
        private static bool setPlayer2Keys;

        #endregion Private fields

        #region Construction

        /// <summary>
        /// Konstruktor
        /// </summary>
        static ConfigDataHelper()
        {
            setPlayer1Keys = true;
            setPlayer2Keys = true;
        }

        #endregion Construction

        #region Public properties

        public static PlayerKeys Player1Keys
        {
            get 
            {
                if (setPlayer1Keys) SetPlayerKeys();
                return player1Keys; 
            }
        }

        public static PlayerKeys Player2Keys
        {
            get 
            {
                if (setPlayer2Keys) SetPlayerKeys();
                return player2Keys; 
            }
        }

        public static bool ShowFPS
        {
            get 
            {
                if (!LoadConfigData())
                    return false;
                else
                    return myData.FPS;
            }
        }

        public static int Particles
        {
            get
            {
                if (!LoadConfigData())
                    return 0;
                else
                    return myData.Particles;
            }
        }

        public static string Language
        {
            get 
            {
                if (!LoadConfigData())
                    return "Deutsch";
                else
                    return myData.Language; 
            }
        }

        public static int Lives 
        { 
            get 
            {
                if (!LoadConfigData())
                    return 5;
                else
                {
                    if (myData.Lives > 0)
                        return myData.Lives;
                    else
                        return 5;
                }
            } 
        }

        public static int WorldSize
        {
            get
            {
                if (!LoadConfigData())
                    return 0;
                else
                    return myData.WorldSize;
            } 
        }

        public static int Asteroids
        {
            get
            {
                if (!LoadConfigData())
                    return 2;
                else
                    return myData.Asteroids;
            } 
        }

        public static int Enemies
        {
            get
            {
                if (!LoadConfigData())
                    return 2;
                else
                    return myData.Enemies;
            } 
        }

        public static float MusicVolume
        {
            get
            {
                if (!LoadConfigData())
                    return 0.5f;
                else
                    return myData.VolumeMusic / 100.0f;
            }
        }

        public static float SfxVolume
        {
            get
            {
                if (!LoadConfigData())
                    return 0.5f;
                else
                    return myData.VolumeSfx / 100.0f;
            }
        }

        #endregion Public properties

        #region Public methods

        public static bool GetResolution(ref int width, ref int height, ref bool fullscreenMode)
        {
            if (!LoadConfigData())
                return false;

            width = myData.ResolutionWidth;
            height = myData.ResolutionHeight;
            fullscreenMode = myData.FullscreenMode;

            return true;
        }

        #endregion Public methods

        #region private methods

        /// <summary>
        /// Laden der Konfigurationsdaten
        /// </summary>
        /// <returns></returns>
        private static bool LoadConfigData()
        {
            if (myData != null)
                return true;
            else
            {
                try
                {
                    myData = DeserializeFromXml();
                    return true;
                }
                catch (Exception)
                {
                    return false;
                }
            }
        }

        /// <summary>
        /// Deserialisierung aus XML-Datei (Laden)
        /// </summary>
        /// <returns></returns>
        private static ConfigData DeserializeFromXml()
        {
            XmlSerializer serializer = new XmlSerializer(typeof(ConfigData));
            string path = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
            FileStream file = new FileStream(path + "\\config.xml", FileMode.Open);
            ConfigData myData = serializer.Deserialize(file) as ConfigData;
            file.Close();
            return myData;
        }

        /// <summary>
        /// Sets the keys for the players
        /// </summary>
        private static void SetPlayerKeys()
        {
            if (!LoadConfigData()) return;

            player1Keys = new PlayerKeys();
            player2Keys = new PlayerKeys();

            player1Keys.upKey       = GetKeysForString(myData.Player1KeyUp);
            player1Keys.downKey     = GetKeysForString(myData.Player1KeyDown);
            player1Keys.leftKey     = GetKeysForString(myData.Player1KeyLeft);
            player1Keys.rightKey    = GetKeysForString(myData.Player1KeyRight);
            player1Keys.fireKey     = GetKeysForString(myData.Player1KeyFire);
            player1Keys.specialKey  = GetKeysForString(myData.Player1KeySpecial);

            player2Keys.upKey       = GetKeysForString(myData.Player2KeyUp);
            player2Keys.downKey     = GetKeysForString(myData.Player2KeyDown);
            player2Keys.leftKey     = GetKeysForString(myData.Player2KeyLeft);
            player2Keys.rightKey    = GetKeysForString(myData.Player2KeyRight);
            player2Keys.fireKey     = GetKeysForString(myData.Player2KeyFire);
            player2Keys.specialKey  = GetKeysForString(myData.Player2KeySpecial);

            setPlayer1Keys = false;
            setPlayer2Keys = false;
        }

        /// <summary>
        /// Strings Konfiguration -> Keys
        /// </summary>
        /// <param name="keyString">Tastenstring wie er im Konfigurationsprogramm benutzt wird</param>
        /// <returns>zugehörige Taste</returns>
        private static Keys GetKeysForString(string keyString)
        {
            switch (keyString)
            {
                case "1": return Keys.D1;
                case "2": return Keys.D2;
                case "3": return Keys.D3;
                case "4": return Keys.D4;
                case "5": return Keys.D5;
                case "6": return Keys.D6;
                case "7": return Keys.D7;
                case "8": return Keys.D8;
                case "9": return Keys.D9;
                case "0": return Keys.D0;

                case "A": return Keys.A;
                case "B": return Keys.B;
                case "C": return Keys.C;
                case "D": return Keys.D;
                case "E": return Keys.E;
                case "F": return Keys.F;
                case "G": return Keys.G;
                case "H": return Keys.H;
                case "I": return Keys.I;
                case "J": return Keys.J;
                case "K": return Keys.K;
                case "L": return Keys.L;
                case "M": return Keys.M;
                case "N": return Keys.N;
                case "O": return Keys.O;
                case "P": return Keys.P;
                case "Q": return Keys.Q;
                case "R": return Keys.R;
                case "S": return Keys.S;
                case "T": return Keys.T;
                case "U": return Keys.U;
                case "V": return Keys.V;
                case "W": return Keys.W;
                case "X": return Keys.X;
                case "Y": return Keys.Y;
                case "Z": return Keys.Z;

                case "Alt links":       return Keys.LeftAlt;
                case "Alt rechts":      return Keys.RightAlt;
                case "Cursor hoch":     return Keys.Up;
                case "Cursor runter":   return Keys.Down;
                case "Cursor links":    return Keys.Left;
                case "Cursor rechts":   return Keys.Right;
                case "Shift links":     return Keys.LeftShift;
                case "Shift rechts":    return Keys.RightShift;
                case "Strg links":      return Keys.LeftControl;
                case "Strg rechts":     return Keys.RightControl;
                case "Enter":           return Keys.Enter;
                case "Leertaste":       return Keys.Space;

                case "Num 0": return Keys.NumPad0;
                case "Num 1": return Keys.NumPad1;
                case "Num 2": return Keys.NumPad2;
                case "Num 3": return Keys.NumPad3;
                case "Num 4": return Keys.NumPad4;
                case "Num 5": return Keys.NumPad5;
                case "Num 6": return Keys.NumPad6;
                case "Num 7": return Keys.NumPad7;
                case "Num 8": return Keys.NumPad8;
                case "Num 9": return Keys.NumPad9;

                case "F1":  return Keys.F1;
                case "F2":  return Keys.F2;
                case "F3":  return Keys.F3;
                case "F4":  return Keys.F4;
                case "F5":  return Keys.F5;
                case "F6":  return Keys.F6;
                case "F7":  return Keys.F7;
                case "F8":  return Keys.F8;
                case "F9":  return Keys.F9;
                case "F10": return Keys.F10;
                case "F11": return Keys.F11;
                case "F12": return Keys.F12;

                default:
                    return Keys.None;
            }
        }

        #endregion Private methods
    }
}
